import {designPage, reactive, VueNode} from "plain-ui-composition";
import {PlAutoComplete, PlIcon, PlLoading, PlSelectOption} from "plain-ui";
import {debounce} from "plain-utils/utils/debounce";
import {defer, DFD} from 'plain-utils/utils/defer'
import './DocSearch.scss'
import {Mdc, processMdc} from "../mdc/process/processMdc";
import {Menu, menus, MenuType} from "./menu";
import {isMdcTable} from "../mdc/process/processTableString";
import {AppNavigator} from "../natigator/app-navigator";

enum eOptionType {
    article = 'article',
    header = 'header',
    mdc = 'mdc',
    api = 'api',
}

const icons: Record<keyof typeof eOptionType, string> = {
    [eOptionType.article]: 'el-icon-paperclip',
    [eOptionType.header]: 'el-icon-place',
    [eOptionType.mdc]: 'el-icon-connection',
    [eOptionType.api]: 'el-icon-link',
}

/**
 * 加载所有的文档
 * @author  韦胜健
 * @date    2021/10/27 22:29
 */
const getSearchData = (() => {
    type SearchSourceData = {
        group?: string,             // 一级菜单名称
        menu: string,               // 二级菜单名称
        path: string,               // 页面路劲
    }
    type SearchFormatData = SearchSourceData & { mdcList: Mdc[] }

    let data: SearchFormatData[];

    return async (): Promise<SearchFormatData[]> => {
        if (!data) {
            const sources: SearchSourceData[] = []

            const iterateMenu = (menu: Menu, group?: Menu) => {
                if (menu.type === MenuType.group) {
                    if (!!menu.menus) {
                        menu.menus.forEach(i => iterateMenu(i, menu))
                    }
                } else {
                    if (!menu.name || !menu.path) {return}
                    sources.push({
                        group: group?.name,
                        menu: [menu.name, menu.tip].join(' '),
                        path: menu.path,
                    })
                }
            }

            menus.forEach(i => iterateMenu(i))

            const result: (SearchSourceData & { text: string })[] = (await Promise.all(sources.map(async source => {
                let text: string;
                try {
                    text = (await import('src/doc/' + source.path + '.md')).default
                } catch (e) {
                    text = ''
                }
                return {
                    ...source,
                    text,
                }
            }))).filter(i => !!i.text)

            data = result.map(({text, ...left}) => ({
                ...left,
                mdcList: processMdc(text)
            }))
        }
        return data
    }
})();

/**
 *
 * @author  韦胜健
 * @date    2021/10/27 22:30
 */
const getMatchText = (source: string, search: string): undefined | { prev?: string, next?: string, text: string } => {
    const index = source.indexOf(search)
    if (index === -1) {
        return undefined
    }
    return {
        prev: source.slice(Math.max(0, index - 6), index),
        next: source.slice(index + search.length, 6),
        text: search,
    }
}

export const DocSearch = designPage(() => {

    interface iSearchOption {
        menu: string,
        header?: string | null,
        type: eOptionType,
        content?: {
            prev?: string,
            next?: string,
            text: string,
        },
        path: string,
    }

    interface iSearchOptionGroup {
        menu: string,
        options: iSearchOption[],
    }

    const searchState = reactive({
        filterMethod: () => true,

        dfd: null as null | DFD,
        searchText: '' as string | null,
        searchGroups: [] as iSearchOptionGroup[],
        empty: (defaultEmpty: () => VueNode) => {
            if (searchState.dfd) {
                return null
            } else {
                if (!searchState.searchText) {
                    return (
                        <div class="pl-background-disabled-text" style={{padding: '12px 0', textAlign: 'center'}}>
                            请输入搜索关键字！
                        </div>
                    )
                }
                return defaultEmpty()
            }
        },
        // 当搜索关键字变化的时候，刷线promise
        onSearchChange: debounce(async (text: string | null) => {
            if (!!searchState.dfd) {
                searchState.dfd.reject('')
                searchState.dfd = null
            }
            searchState.searchText = text
            if (!text) {
                searchState.searchGroups = []
            } else {
                // 这里模拟网络异步请求动作，等待1s~2s得到匹配的数据
                searchState.dfd = defer<any[]>()
                const searchData = await getSearchData()
                const searchGroups: iSearchOptionGroup[] = []
                searchData.forEach(({menu, mdcList, path}) => {
                    const searchGroup: iSearchOptionGroup = {menu, options: []}
                    if (menu.indexOf(text) > -1) {
                        // 匹配文章
                        searchGroup.options.push({menu, type: eOptionType.article, path})
                    }
                    mdcList.forEach(mdc => {
                        if (typeof mdc === "string") {
                            const textList = mdc.replace('-', '').split('\n').filter(Boolean)
                            let prevHeader: string | null = null
                            textList.forEach((item) => {
                                if (item.indexOf('## ') === 0) {
                                    prevHeader = item.slice(3)
                                }
                                if (item.indexOf(text) > -1) {
                                    // 匹配标题
                                    searchGroup.options.push({menu, content: getMatchText(item, text)!, path: !!prevHeader ? `${path}#${prevHeader}` : path, header: prevHeader, type: eOptionType.header})
                                }
                            })
                        } else {
                            if (!mdc.title) {return}
                            if (isMdcTable(mdc)) {
                                // 处理mdc的title
                                if (mdc.title.indexOf(text) > -1) {
                                    // 匹配MDC
                                    searchGroup.options.push({menu, content: getMatchText(mdc.title, text), path: `${path}#API：${mdc.title}`, header: mdc.title, type: eOptionType.api})
                                }
                                const matchText = mdc.content.split(/[|\s]/g).filter(i => Boolean(i.trim())).find(i => i.indexOf(text) > -1)
                                if (matchText) {
                                    // 匹配API
                                    searchGroup.options.push({menu, content: getMatchText(matchText, text), path: `${path}#API：${mdc.title}`, header: mdc.title, type: eOptionType.api})
                                }
                            } else {
                                // 处理mdc的title
                                if (mdc.title.indexOf(text) > -1) {
                                    // 匹配MDC
                                    searchGroup.options.push({menu, content: getMatchText(mdc.title, text), path: `${path}#${mdc.title}`, header: mdc.title, type: eOptionType.mdc})
                                }
                                const {title, desc, bottomDesc, content, template} = mdc;
                                [desc, bottomDesc, content, template].forEach(source => {
                                    if (!!source) {
                                        const matchContent = getMatchText(source, text)
                                        if (!!matchContent) {
                                            // 匹配MDC
                                            searchGroup.options.push({menu, content: matchContent, path: `${path}#${title}`, header: title, type: eOptionType.mdc})
                                        }
                                    }
                                })
                            }
                        }
                    })

                    if (searchGroup.options.length > 0) {
                        searchGroups[menu.indexOf(text) > -1 ? 'unshift' : 'push'](searchGroup)
                    }
                })
                // console.log(searchGroups)
                searchState.searchGroups = searchGroups
                searchState.dfd = null
            }
        }, 300),
        onClickOption: (opt: iSearchOption) => {
            console.log(JSON.stringify(opt))
            AppNavigator.go(opt.path.trim())
        },
        onBlur: () => {
            // searchState.searchGroups = []
        }
    })

    /*onMounted(() => {
        searchState.onSearchChange('自定义')
    })*/

    return () => (
        <PlAutoComplete
            class="doc-search"
            inputProps={{prefixIcon: 'el-icon-search', suffixIcon: null as any, placeholder: '搜索', clearIcon: null as any}}
            modelValue={searchState.searchText!}
            filterMethod={searchState.filterMethod}
            empty={searchState.empty}
            popperAttrs={{
                popperClass: `doc-search-popper`,
                sizeEqual: false,
                width: 400,
                height: (searchState.searchGroups.reduce((prev, group) => prev + group.options.length, 0)) < 6 ? null as any : 450,
            }}
            onInputChange={searchState.onSearchChange}
            onBlur={searchState.onBlur}
        >
            {!!searchState.dfd ? (
                <div class="pl-background-disabled-text" style={{display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '12px 0'}}>
                    <PlLoading style={{fontSize: '24px'}}/>
                    <span>数据加载中</span>
                </div>
            ) : (
                searchState.searchGroups.map((group, groupIndex) => (
                    <div key={groupIndex} class="doc-search-group">
                        <p class="doc-search-group-name">{group.menu}</p>
                        <div class="doc-search-group-list">
                            {group.options.map((opt, optIndex) => (!opt.content ? null :
                                    <PlSelectOption label={opt.menu} val={opt.content.text} key={optIndex} onClick={() => searchState.onClickOption(opt)}>
                                        {!!opt.content && (
                                            <p class="doc-search-group-content">
                                                <span>{opt.content.prev}</span>
                                                <span class="doc-search-group-content-text">{opt.content.text}</span>
                                                <span>{opt.content.next}</span>
                                            </p>
                                        )}
                                        {!!opt.header && <p class="doc-search-group-header">{opt.header}</p>}
                                        <div class="doc-search-type">
                                            <PlIcon icon={icons[opt.type]}/>
                                        </div>
                                    </PlSelectOption>
                            ))}
                        </div>
                    </div>
                ))
            )}
        </PlAutoComplete>
    )
})
